﻿using es.typescript.plug;
using Jurassic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace es.typescript
{
    public class TSEngine
    {
        /// <summary>
        /// ts编译器
        /// </summary>
        TypeScriptCompiler tsCompiler;

        /// <summary>
        /// js运行器
        /// </summary>
        JavaScriptExecutor jsExecutor;



        public TSEngine()
        {
            tsCompiler = new TypeScriptCompiler();
            jsExecutor = new JavaScriptExecutor();
        }


        /// <summary>
        /// 初始化引擎
        /// </summary>
        /// <returns></returns>
        public async Task Init()
        {
            await tsCompiler.InitializeCompilerAsync();
        }






        #region 扩展对象

        #region opencv

        /// <summary>
        /// 启动opencv对象"cv"
        /// </summary>
        public void EnableOpencv()
        {
            cv = new opencv();
            SetObject("cv", cv);
        }
        opencv cv;

        #endregion





        /// <summary>
        /// 启用控制台"console"
        /// </summary>
        public void EnableConsole()
        {
            jsExecutor.EnableConsoleApi();
        }


        #endregion



        #region 交互

        /// <summary>
        /// 注册对象
        /// </summary>
        /// <param name="name"></param>
        /// <param name="obj"></param>
        public void SetObject(string name, object obj)
        {
            jsExecutor.SetObject(name, obj);
        }

        /// <summary>
        /// 注册函数
        /// </summary>
        /// <param name="name"></param>
        /// <param name="fun"></param>
        public void SetFunction(string name, Action fun)
        {
            jsExecutor.SetFunction(name, fun);
        }

        /// <summary>
        /// 获取对象
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public object GetObject(string name)
        {
            return jsExecutor.GetObject(name);
        }

        /// <summary>
        /// 获取对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        public T GetObject<T>(string name)
        {
            return jsExecutor.GetObject<T>(name);
        }

        /// <summary>
        /// 调用脚本函数
        /// </summary>
        /// <param name="func"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public object CallFunc(string func, params object[] args)
        {
            return jsExecutor.CallFunc(func, args);
        }


        /// <summary>
        /// 调用脚本函数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public T CallFunc<T>(string func, params object[] args)
        {
            return jsExecutor.CallFunc<T>(func, args);
        }

        #endregion



        #region 编译运行


        /// <summary>
        /// 编译到js
        /// </summary>
        /// <param name="ts"></param>
        /// <returns></returns>
        public async Task<string> Compile2js(string ts)
        {
            return await tsCompiler.Compile2JsAsync(ts);
        }



        /// <summary>
        /// 编译ts源码
        /// </summary>
        /// <param name="ts"></param>
        /// <returns></returns>
        public async Task<CompiledScript> Compile(string ts)
        {
            //编译为js
            string js = await Compile2js(ts);

            //编译为可运行脚本
            return await jsExecutor.CompileAsync(js);
        }


        /// <summary>
        /// 执行
        /// </summary>
        /// <param name="script"></param>
        /// <returns></returns>
        public async Task Execute(CompiledScript script)
        {
            await Task.Run(() => script.Execute());
        }



        /// <summary>
        /// 执行ts
        /// </summary>
        /// <param name="ts"></param>
        /// <returns></returns>
        public async Task Execute(string ts)
        {
            var script = await Compile(ts);
            await Execute(script);
        }

        #endregion
    }
}
